package com.shoulder.imports;

import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static com.google.auto.common.MoreElements.getAnnotationMirror;
import static com.google.common.base.Throwables.getStackTraceAsString;
import static com.shoulder.imports.ImportsFiles.SPRING_IMPORTS_FILE_PATH;
import static com.shoulder.imports.ImportsHelper.*;

/**
 * 这里是直接抄的谷歌的 AutoService，请注意:不是借鉴
 */
@SupportedOptions({"debug", "verify"})
public class ImportsProcessor extends AbstractProcessor {


    private final List<String> exceptionStacks = Collections.synchronizedList(new ArrayList<>());

    private final SetMultimap<String, String> importsMap = HashMultimap.create();

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public ImmutableSet<String> getSupportedAnnotationTypes() {
        return ImmutableSet.of(Imports.class.getName());
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        try {
            processImpl(annotations, roundEnv);
        } catch (RuntimeException e) {
            // We don't allow exceptions of any kind to propagate to the compiler
            String trace = getStackTraceAsString(e);
            exceptionStacks.add(trace);
            fatalError(processingEnv, trace);
        }
        return false;
    }

    private void processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (roundEnv.processingOver()) {
            generateImportFile();
        } else {
            processAnnotations(annotations, roundEnv);
        }
    }

    private void processAnnotations(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Imports.class);
        log(processingEnv, annotations.toString());
        log(processingEnv, elements.toString());
        if (elements.isEmpty()) {
            return;
        }
        for (Element e : elements) {
            //获取被 @Imports 注解标记的类
            TypeElement providerImplementer = MoreElements.asType(e);
            //获取该类上的注解详细信息
            AnnotationMirror annotationMirror = getAnnotationMirror(e, Imports.class).get();
            Set<DeclaredType> providerInterfaces = getValueFieldOfClasses(annotationMirror);
            if (providerInterfaces.isEmpty()) {
                error(processingEnv, "No import interfaces provided for element!", e, annotationMirror);
                continue;
            }
            for (DeclaredType providerInterface : providerInterfaces) {
                TypeElement providerType = MoreTypes.asTypeElement(providerInterface);
                log(processingEnv, "provider interface: " + providerType.getQualifiedName());
                log(processingEnv, "provider implementer: " + providerImplementer.getQualifiedName());
                //标记在 @Imports 上 value 属性的 class
                String providerTypeName = getBinaryName(providerType);
                //被  @Imports 标记的类
                String implementerName = getBinaryName(providerImplementer);
                if (!importsMap.containsValue(implementerName)) {
                    importsMap.put(ImportsFilesEnums.match(providerTypeName).getFile(), implementerName);
                }

            }
        }
//        Set<TypeElement> elements = roundEnv.getRootElements()
//                .parallelStream()
//                .filter(e -> e instanceof TypeElement)
//                .map(el -> (TypeElement) el)
//                .filter(el -> el.getKind().isClass() || el.getKind().isInterface())
//                .filter(el -> el.getQualifiedName().toString().startsWith("com.shoulder"))
//                .filter(el -> {
//                    List<? extends AnnotationMirror> mirrors = el.getAnnotationMirrors();
//                    List<String> list = mirrors.stream().map(each -> each.getAnnotationType().toString()).toList();
//                    return list.contains(ImportsFiles.ANNOTATION_NAME);
//                })
//                .collect(Collectors.toSet());
//        if (elements.isEmpty()) {
//            return;
//        }
//        log(annotations.toString());
//        log(elements.toString());
//        //将符合项目要求的配置类放入到 map 中,方便配置文件的自动生成
//        for (TypeElement e : elements) {
//            String className = e.getQualifiedName().toString();
//            if (!importsMap.containsValue(className)) {
//                importsMap.put(ImportsFiles.ANNOTATION_NAME, className);
//            }
//        }
    }

    private void generateImportFile() {
        if (importsMap.isEmpty()) {
            return;
        }
        Filer filer = processingEnv.getFiler();
        FileObject fileObject;
        try {
            fileObject = filer.createResource(StandardLocation.CLASS_OUTPUT, "", SPRING_IMPORTS_FILE_PATH);
            OutputStream out = fileObject.openOutputStream();
            ImportsFiles.writeImportFile(importsMap.values(), out);
        } catch (IOException e) {
            fatalError(processingEnv, "生成配置文件出错");
        }
    }


}
